package cn.qu.dockman.agent.ws;

import cn.qu.dockman.agent.util.DockmanClient;
import cn.qu.dockman.protocol.command.Command;
import cn.qu.dockman.protocol.command.client.RegisterCommand;
import cn.qu.dockman.protocol.command.server.ContainerServiceCommand;
import cn.qu.dockman.protocol.def.CommandFactory;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.exceptions.WebsocketNotConnectedException;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import java.net.URI;

public class WebSocket implements InitializingBean, DisposableBean {
    private static final Logger logger = LoggerFactory.getLogger(Logger.class);

    private WebSocketClient webSocketClient;

    private URI serverURI;
    private DockmanClient dockmanClient;

    public WebSocket(URI serverURI, DockmanClient dockmanClient) {
        this.serverURI = serverURI;
        this.dockmanClient = dockmanClient;
    }
    private String token;

    public void onOpen(ServerHandshake handshakedata) {
        send(RegisterCommand.create(token).toString());
    }

    public void send(String text) {
        if (webSocketClient != null) {
            try {
                webSocketClient.send(text);
            } catch (WebsocketNotConnectedException e) {
                try {
                    reconnect();
                } catch (InterruptedException e1) {

                }
            } catch (Exception e) {
                logger.error("发送消息失败：" + text, e);
            }
        } else {
            logger.error("无连接：{}", this.serverURI);
        }
    }

    public void onMessage(String message) {
        Command cmd = CommandFactory.getCommand(message);
        if (cmd instanceof ContainerServiceCommand) {
            ContainerServiceCommand command = (ContainerServiceCommand) cmd;
            ContainerServiceCommand.ContainerServiceBody[] bodys = command.getBody();
            for (ContainerServiceCommand.ContainerServiceBody body : bodys) {

                if (body.getType() == ContainerServiceCommand.Type.START) {
                    dockmanClient.startContainerCmd(body.getContainerId()).exec();
                } else if (body.getType() == ContainerServiceCommand.Type.STOP) {
                    dockmanClient.stopContainerCmd(body.getContainerId()).exec();
                }
            }
        }
    }

    public void onClose(int code, String reason, boolean remote) {
        logger.info("来自 {} 的连接已断开,尝试重连...", this.serverURI);
    }

    public void onError(Exception ex) {
        ex.printStackTrace();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        reconnect();
    }

    public void destroy() {
        if (webSocketClient != null) {
            webSocketClient.close();
        }
    }

    protected void reconnect() throws InterruptedException {
        if (webSocketClient != null) {
            webSocketClient.close();
        }
        Thread.sleep(1 * 1000);

        logger.info("正在连接 {} ...", this.serverURI);
        webSocketClient = new WebSocketClient(serverURI) {
            @Override
            public void onOpen(ServerHandshake handshakedata) {
                WebSocket.this.onOpen(handshakedata);
            }

            @Override
            public void onMessage(String message) {
                WebSocket.this.onMessage(message);
            }

            @Override
            public void onClose(int code, String reason, boolean remote) {
                WebSocket.this.onClose(code, reason, remote);
            }

            @Override
            public void onError(Exception ex) {
                WebSocket.this.onError(ex);
            }
        };
        try {
            if (webSocketClient.connectBlocking()) {
                logger.info("已连接到 {} ", this.serverURI);
            } else {
                logger.error("连接 {} 失败", this.serverURI);
                reconnect();
            }
        } catch (Exception e) {
            logger.error("连接{}失败,异常原因:{}", this.serverURI, e.getMessage());
            reconnect();
        }
    }

    public void setToken(String token) {
        this.token = token;
    }
}
